package com.tau.iplayer.client.algorithms;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.tau.iplayer.client.models.Track;

public class BayesianAverageRatingCalc implements
		AverageRatingsCalculatorStrategy {

	@Override
	public List<Track> calcAvgRatings(List<Track> tracks) {
		List<Track> results = new ArrayList<Track>();
		Track currentTrack = new Track();
		/* Parameters for calculating the Bayesian average */
		double ratingSum = 0;
		double ratingAvg = 0;
		int n = 0;
		double W = 0;
		double m = 0;
		double C = 0;
		double ttlSum = 0;
		int counter = 0;
		int numOfSongs = 0;
		Map<Track, Integer> numOfOccurences = new HashMap<Track, Integer>();
		for (Track track : tracks) {
			counter++;
			if (track.getId().equals(currentTrack.getId())) {
				ratingSum = ratingSum + track.getRating();
				n++;
			} else {
				/* Finished going over a certain track */
				numOfSongs++;
				if (n != 0) {
					ratingAvg = ratingSum / n;
					Track item = new Track(currentTrack.getTitle(),
							currentTrack.getArtist(), currentTrack
									.getDuration(), currentTrack.getVideoID(),
							currentTrack.getThumbnailURL(), ratingAvg);
					numOfOccurences.put(item, n);
					results.add(item);
				}
				m = m + n;
				m = m / numOfSongs;
				currentTrack = track;
				ttlSum += ratingSum;
				ratingSum = track.getRating();
				n = 1;
			}
		}
		if (n != 0) {
			ratingAvg = ratingSum / n;
			Track item = new Track(currentTrack.getTitle(), currentTrack
					.getArtist(), currentTrack.getDuration(), currentTrack
					.getVideoID(), currentTrack.getThumbnailURL(), ratingAvg);
			numOfOccurences.put(item, n);
			results.add(item);
			m = m + n;
			ttlSum += ratingSum;
			C = ttlSum / counter;
		}
		for (Track item : results) {
			/* Calculate weighted Bayesian average */
			n = numOfOccurences.get(item);
			W = (n / (n + m)) * item.getRating() + (m / (n + m)) * C;
			item.setRating(W);
		}
		Collections.sort(results, new Comparator<Track>() {

			@Override
			public int compare(Track o1, Track o2) {
				return (int) (o1.getRating() - o2.getRating());
			}
		});
		Collections.reverse(results);
		return results;
	}

}
